package com.william.jdbcplus.core.condition.lambda;

import com.william.jdbcplus.core.toolkit.lambda.support.SFunction;

import java.io.Serializable;
import java.util.Collection;
import java.util.function.Function;

/**
 * Where 片段
 *
 * @author niliwei
 */
public interface Where<Wrap> extends Serializable {

    /**
     * 等于
     * column = val
     *
     * @param column 列
     * @param val    值
     * @return
     */
    <R> Wrap eq(SFunction<R, ?> column, Object val);

    /**
     * 等于
     * column = ( wrap.getAll() )
     *
     * @param column 列
     * @param func   子查询
     * @return
     */
    <R> Wrap eq(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * 不等于 <>
     *
     * @param column 列
     * @param val    值
     * @return
     */
    <R> Wrap ne(SFunction<R, ?> column, Object val);

    /**
     * 不等于 <>
     *
     * @param column 列
     * @param func   子查询
     * @return
     */
    <R> Wrap ne(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * 大于  >
     *
     * @param column 列
     * @param val    值
     * @return
     */
    <R> Wrap gt(SFunction<R, ?> column, Object val);

    /**
     * 大于  >
     *
     * @param column 列
     * @param func   子查询
     * @return
     */
    <R> Wrap gt(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * 大于等于  >=
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap ge(SFunction<R, ?> column, Object val);

    /**
     * 大于等于  >=
     *
     * @param column
     * @param func   子查询
     * @return
     */
    <R> Wrap ge(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * 小于  <
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap lt(SFunction<R, ?> column, Object val);

    /**
     * 小于  <
     *
     * @param column
     * @param func   子查询
     * @return
     */
    <R> Wrap lt(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * 小于等于  <=
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap le(SFunction<R, ?> column, Object val);

    /**
     * 小于等于  <=
     *
     * @param column
     * @param func   子查询
     * @return
     */
    <R> Wrap le(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * BETWEEN 值1 AND 值2
     *
     * @param column
     * @param val1
     * @param val2
     * @return
     */
    <R> Wrap between(SFunction<R, ?> column, Object val1, Object val2);

    /**
     * NOT BETWEEN 值1 AND 值2
     *
     * @param column
     * @param val1
     * @param val2
     * @return
     */
    <R> Wrap notBetween(SFunction<R, ?> column, Object val1, Object val2);

    /**
     * LIKE '%值%'
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap like(SFunction<R, ?> column, Object val);

    /**
     * NOT LIKE '%值%'
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap notLike(SFunction<R, ?> column, Object val);

    /**
     * LIKE '%值'
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap likeLeft(SFunction<R, ?> column, Object val);

    /**
     * LIKE '值%'
     *
     * @param column
     * @param val
     * @return
     */
    <R> Wrap likeRight(SFunction<R, ?> column, Object val);

    /**
     * IN (col1, col2...)
     *
     * @param column
     * @param collValues
     * @return
     */
    <R> Wrap in(SFunction<R, ?> column, Collection<?> collValues);

    /**
     * NOT IN (col1, col2...)
     *
     * @param column
     * @param collValues
     * @return
     */
    <R> Wrap notIn(SFunction<R, ?> column, Collection<?> collValues);

    /**
     * 为空
     *
     * @param column
     * @return
     */
    <R> Wrap isNull(SFunction<R, ?> column);

    /**
     * 非空
     *
     * @param column
     * @return
     */
    <R> Wrap isNotNull(SFunction<R, ?> column);

    /**
     * on条件
     * <p> select * from tab1, tab2 where tab1.id = tab2.id</p>
     *
     * @param r1 左列
     * @param r2 右列
     * @return
     */
    <R, R2> Wrap on(SFunction<R, ?> r1, SFunction<R2, ?> r2);

    /**
     * 连接 not
     *
     * @return
     */
    Wrap not();

    /**
     * 连接 or
     *
     * @return
     */
    Wrap or();

    /**
     * 连接 and
     *
     * @return
     */
    Wrap and();

    /**
     * NOT 嵌套
     * <p>
     * 例: not(i -> i.eq("name", "李白").ne("status", "活着"))
     * 等价于 not ( name = '李白' and status != '活着')
     * </p>
     *
     * @param func 函数
     * @return wrap
     */
    Wrap not(Function<Wrap, Wrap> func);

    /**
     * OR
     * <p>
     * 例: or(i -> i.eq("name", "李白").ne("status", "活着"))
     * 等价于 or (name = '李白' and status != '活着')
     * </p>
     *
     * @param func 函数
     * @return wrap
     */
    Wrap or(Function<Wrap, Wrap> func);

    /**
     * OR 嵌套
     * <p>
     * 例: orNest(i -> i.eq("name", "李白").ne("status", "活着"), e-> e.eq("id", 1).lt("num", 2))
     * 等价于 (( name = '李白' and status != '活着' ) or ( id = 1 and num < 2))
     * </p>
     *
     * @param functions 函数
     * @return wrap
     */
    Wrap orNest(Function<Wrap, Wrap>... functions);

    /**
     * AND
     * <p>
     * 例: and(i -> i.eq("name", "李白").ne("status", "活着"))
     * 等价于 and (name = '李白' and status != '活着')
     * </p>
     *
     * @param func 函数
     * @return wrap
     */
    Wrap and(Function<Wrap, Wrap> func);

    /**
     * AND 嵌套
     * <p>
     * 例: andNest(i -> i.eq("name", "李白").or().ne("status", "活着"), e-> e.eq("id", 1).lt("num", 2))
     * 等价于 (( name = '李白' or status != '活着' ) and ( id = 1 and num < 2))
     * </p>
     *
     * @param functions 函数
     * @return wrap
     */
    Wrap andNest(Function<Wrap, Wrap>... functions);

    /**
     * 正常嵌套 不带 AND 或者 OR
     * <p>
     * 例: link(i -> i.eq("name", "李白").ne("status", "活着"))
     * </p>
     *
     * @param func 函数
     * @return Wrap
     */
    Wrap link(Function<Wrap, Wrap> func);

    /**
     * IN (wrap.getSql())
     *
     * @param column
     * @param func
     * @return
     */
    <R> Wrap in(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * not IN (wrap.getSql())
     *
     * @param column
     * @param func
     * @return
     */
    <R> Wrap notIn(SFunction<R, ?> column, Function<Wrap, Wrap> func);

    /**
     * exists (wrap.getSql())
     *
     * @param func
     * @return
     */
    Wrap exists(Function<Wrap, Wrap> func);

    /**
     * 拼接 NOT EXISTS (wrap.getSql())
     *
     * @param func
     * @return
     */
    Wrap notExists(Function<Wrap, Wrap> func);

    /**
     * 拼接 sql
     * <p>!! 会有 sql 注入风险 !!</p>
     * <p>例1: apply("id = 1")</p>
     * <p>例2: apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")</p>
     * <p>例3: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", LocalDate.now())</p>
     *
     * @param sql   脚本
     * @param value
     * @return
     */
    Wrap connect(String sql, Object... value);

}